package tar

import (
	"archive/tar"
	"compress/gzip"
	"io"
	"os"
	"path/filepath"
	"strings"

	msio "gitee.com/yrwy/msgo/pkg/io"
)

func Compress(dest string, src ...string) error {
	d, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer func() {
		d.Close()
		if err != nil {
			os.Remove(dest)
		}
	}()
	var tw *tar.Writer
	if len(dest) > 7 && strings.EqualFold(dest[len(dest)-7:], ".tar.gz") {
		gw := gzip.NewWriter(d)
		defer gw.Close()
		tw = tar.NewWriter(gw)
	} else {
		tw = tar.NewWriter(d)
	}
	defer tw.Close()
	for _, srcFile := range src {
		baseDir := filepath.Dir(srcFile) + "/"
		baseDir = strings.ReplaceAll(baseDir, "\\", "/")
		err = filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
			if path == "." || path == ".." {
				return nil
			}
			if err != nil {
				return err
			}
			//获取压缩头信息
			header, err := tar.FileInfoHeader(info, "")
			if err != nil {
				return err
			}
			path = strings.ReplaceAll(path, "\\", "/") //必须使用正斜杠而不是反斜杠
			header.Name = strings.TrimPrefix(path, baseDir)
			if info.IsDir() {
				header.Name += "/"
			}
			err = tw.WriteHeader(header)
			if err != nil {
				return err
			}
			if !info.IsDir() {
				file, err := os.Open(path)
				if err != nil {
					return err
				}
				defer file.Close()
				_, err = io.Copy(tw, file)
			}
			return err
		})
	}
	return nil
}

func _decompress(tr *tar.Reader, dest string) ([]string, error) {
	var ret []string
	for {
		h, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return ret, err
			}
		}
		filename := filepath.Join(dest, h.Name)
		if h.FileInfo().IsDir() {
			err = os.MkdirAll(filename, 0755)
			if err != nil {
				return ret, err
			}
			continue
		}
		file, err := msio.Create(filename, os.FileMode(h.Mode))
		if err != nil {
			return ret, err
		}
		io.Copy(file, tr)
		file.Close()
		ret = append(ret, filename)
	}
	return ret, nil
}

func DecompressGz(r io.Reader, dest string) ([]string, error) {
	gr, err := gzip.NewReader(r)
	if err != nil {
		return nil, err
	}
	defer gr.Close()
	return _decompress(tar.NewReader(gr), dest)
}

func DecompressTar(r io.Reader, dest string) ([]string, error) {
	return _decompress(tar.NewReader(r), dest)
}

func Decompress(tarFile, dest string) ([]string, error) {
	srcFile, err := os.Open(tarFile)
	if err != nil {
		return nil, err
	}
	defer srcFile.Close()

	var tr *tar.Reader
	if len(tarFile) > 7 && strings.EqualFold(tarFile[len(tarFile)-7:], ".tar.gz") {
		gr, err := gzip.NewReader(srcFile)
		if err != nil {
			return nil, err
		}
		defer gr.Close()
		tr = tar.NewReader(gr)
	} else {
		tr = tar.NewReader(srcFile)
	}
	return _decompress(tr, dest)
}
